package org.jeecg.modules.scheduling.controller;

import java.text.SimpleDateFormat;
import java.time.*;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.stream.IntStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.classes.entity.Classes;
import org.jeecg.modules.classes.service.IClassesService;
import org.jeecg.modules.clockRecord.entity.ClockRecord;
import org.jeecg.modules.clockRecord.service.IClockRecordService;
import org.jeecg.modules.employee.entity.Employee;
import org.jeecg.modules.employee.service.IEmployeeService;
import org.jeecg.modules.identificationRecord.entity.IdentificationRecord;
import org.jeecg.modules.identificationRecord.service.IIdentificationRecordService;
import org.jeecg.modules.scheduling.entity.*;
import org.jeecg.modules.scheduling.service.ISchedulingService;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;

import org.jeecg.modules.system.service.ISysUserService;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.jeecg.common.system.base.controller.JeecgController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.fastjson.JSON;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.jeecg.common.aspect.annotation.AutoLog;

/**
 * @Description: 排班表
 * @Author: jeecg-boot
 * @Date: 2025-01-21
 * @Version: V1.0
 */
@Api(tags = "排班表")
@RestController
@RequestMapping("/scheduling/scheduling")
@Slf4j
public class SchedulingController extends JeecgController<Scheduling, ISchedulingService> {
    @Autowired
    private ISchedulingService schedulingService;
    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private IEmployeeService employeeService;
    @Autowired
    private IClassesService classesService;
    @Autowired
    private IClockRecordService clockRecordService;
    @Autowired
    private IIdentificationRecordService identificationRecordService;

    /**
     * 分页列表查询
     *
     * @param scheduling
     * @param pageNo
     * @param pageSize
     * @param req
     * @return
     */
    @ApiOperation(value = "排班表-分页列表查询", notes = "排班表-分页列表查询")
    @GetMapping(value = "/list")
    public Result<?> queryPageList(Scheduling scheduling,
                                   @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                   @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                                   HttpServletRequest req) {
        QueryWrapper<Scheduling> queryWrapper = QueryGenerator.initQueryWrapper(scheduling, req.getParameterMap());
        Page<Scheduling> page = new Page<Scheduling>(pageNo, pageSize);
        IPage<Scheduling> pageList = schedulingService.page(page, queryWrapper);
        return Result.OK(pageList);
    }

    @ApiOperation(value = "排班表-获取排班记录", notes = "排班表-获取排班记录")
    @GetMapping(value = "/getSchedulingRecord")
    public Result<?> getSchedulingRecord(@RequestParam(name = "month") String month,
                                         @RequestParam(name = "name", required = false) String name,
                                         @RequestParam(name = "workNumber", required = false) String workNumber,
                                         @RequestParam(name = "departmentId", required = false) String departmentId) {
        List<EmployeeSchedule> rawData = schedulingService.getSchedulingRecord(month, name, workNumber, departmentId);
        return Result.OK(rawData);
    }

    /**
     * 添加
     *
     * @param scheduling
     * @return
     */
    @AutoLog(value = "排班表-添加")
    @ApiOperation(value = "排班表-添加", notes = "排班表-添加")
    @PostMapping(value = "/add")
    public Result<?> add(@RequestBody Scheduling scheduling) {
        schedulingService.save(scheduling);
        return Result.OK("添加成功！");
    }

    @AutoLog(value = "排班表-延续排班")
    @ApiOperation(value = "排班表-延续排班", notes = "排班表-延续排班")
    @PostMapping(value = "/perpetuate")
    public Result<?> perpetuate(@RequestBody SchedulingDTO schedulingDTO) {
        List<String> checkedKeys = schedulingDTO.getCheckedKeys();

        List<Scheduling> schedules = new ArrayList<>();
        List<Scheduling> today = new ArrayList<>();
        String s = DateUtils.formatDate();
        for (String admitGuid : checkedKeys) {
            Scheduling scheduling = schedulingService.getLastByAdmitGuid(admitGuid);
            Date date = scheduling.getDate();
            List<Date> workDaysNextWeek = getWorkDaysNextWeek(date);
            for (Date day : workDaysNextWeek) {
                Scheduling schedule = new Scheduling();
                schedule.setAdmitGuid(admitGuid);
                schedule.setClassesId(scheduling.getClassesId());
                schedule.setDate(day); // 设置转换后的 java.util.Date
                schedules.add(schedule);
                if (s.equals(DateUtils.formatDate(day))) {
                    ClockRecord todayByAdmitGuid = clockRecordService.getTodayByAdmitGuid(admitGuid);
                    if (todayByAdmitGuid == null) {
                        today.add(schedule);
                    }
                }
            }
        }
        schedulingService.saveBatch(schedules);
        new Thread(() -> {
            createAndSaveClockRecord(today);
        }).start();
        return Result.OK("保存成功！");
    }

    public static List<Date> getWorkDaysNextWeek(Date startDate) {
        // 找到下一个周一的日期
        LocalDate nextMonday = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        while (nextMonday.getDayOfWeek() != DayOfWeek.MONDAY) {
            nextMonday = nextMonday.plusDays(1);
        }

        // 生成周一到周五的日期列表
        List<Date> dates = new ArrayList<>();
        LocalDate currentDate = nextMonday;
        for (int i = 0; i < 5; i++) {
            // 转换为Date类型（使用系统默认时区）
            Date date = Date.from(currentDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
            dates.add(date);
            currentDate = currentDate.plusDays(1);
        }

        return dates;
    }

    @AutoLog(value = "排班表-保存排班规则")
    @ApiOperation(value = "排班表-保存排班规则", notes = "排班表-保存排班规则")
    @PostMapping(value = "/adds")
    @Transactional(rollbackFor = Exception.class)
    public Result<?> adds(@RequestBody SchedulingDTO schedulingDTO) {
        // 解析并验证输入数据
        List<String> checkedKeys = schedulingDTO.getCheckedKeys();
        String selectClasses = schedulingDTO.getSelectClasses();
        List<String> dateStrings = schedulingDTO.getDates();

        // 将日期字符串转换为 Instant 对象，然后转换为 java.util.Date
        List<Date> dates = dateStrings.stream()
                .map(dateStr -> {
                    LocalDate localDate = LocalDate.parse(dateStr.substring(0, 10)); // 假定日期格式为"yyyy-MM-dd"
                    return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
                })
                .collect(Collectors.toList());

        // 构建实体对象
        List<Scheduling> schedules = new ArrayList<>();
        List<Scheduling> today = new ArrayList<>();
        String s = DateUtils.formatDate();
        for (String admitGuid : checkedKeys) {
            for (Date date : dates) {
                Scheduling schedule = new Scheduling();
                schedule.setAdmitGuid(admitGuid);
                schedule.setClassesId(selectClasses);
                schedule.setDate(date); // 设置转换后的 java.util.Date
                schedules.add(schedule);
                if (s.equals(DateUtils.formatDate(date))) {
                    ClockRecord todayByAdmitGuid = clockRecordService.getTodayByAdmitGuid(admitGuid);
                    if (todayByAdmitGuid == null) {
                        today.add(schedule);
                    }
                }
            }
        }
        LambdaQueryWrapper<Scheduling> wrapper = Wrappers.lambdaQuery();
        wrapper.in(Scheduling::getAdmitGuid, checkedKeys);
        wrapper.in(Scheduling::getDate, dates);
        schedulingService.remove(wrapper);
        schedulingService.saveBatch(schedules);
        new Thread(() -> {
            createAndSaveClockRecord(today);
            updateExistClockRecord(checkedKeys, selectClasses, dates);
        }).start();
        return Result.OK("保存成功！");
    }

    private void updateExistClockRecord(List<String> checkedKeys, String selectClasses, List<Date> dates) {
        LambdaQueryWrapper<ClockRecord> wrapper = Wrappers.lambdaQuery();
        wrapper.in(ClockRecord::getAdmitGuid, checkedKeys);
        wrapper.in(ClockRecord::getDate, dates);
        List<ClockRecord> clockRecords = clockRecordService.list(wrapper);
        Classes byId = classesService.getById(selectClasses);
        String startTime = byId.getStartTime();
        for (ClockRecord clockRecord : clockRecords) {
            clockRecord.setClassesId(selectClasses);
            clockRecord.setClassesType(byId.getClassesType());
            String inTime = clockRecord.getInTime();
            if (!StringUtils.isEmpty(inTime)){
                if (inTime.compareTo(startTime) <= 0) {
                    clockRecord.setAbnormalType(1).setAbnormal(0);
                } else {
                    clockRecord.setAbnormalType(3).setAbnormal(1);
                }
            }
        }
        clockRecordService.updateBatchById(clockRecords);
    }

    private void createAndSaveClockRecord(List<Scheduling> list) {
        if (list.isEmpty()) {
            return;
        }
        List<ClockRecord> saveList = new ArrayList<>();
        // 获取当前日期
        LocalDate today = LocalDate.now();
        // 将当前日期时间设置为今天的开始时间，并转换为系统默认时区的ZonedDateTime
        ZonedDateTime startOfDay = today.atStartOfDay(ZoneId.systemDefault());
        // 转换为Date对象
        Date date = Date.from(startOfDay.toInstant());
        for (Scheduling scheduling : list) {
            String admitGuid = scheduling.getAdmitGuid();
            String classesId = scheduling.getClassesId();
            Employee byAdmitGuid = employeeService.getByAdmitGuid(admitGuid);
            Classes byId = classesService.getById(classesId);
            ClockRecord clockRecord = new ClockRecord();
            clockRecord.setDate(date)
                    .setAdmitGuid(admitGuid).setDept(byAdmitGuid.getDept()).setClassesId(classesId)
                    .setAdmitName(byAdmitGuid.getName()).setFaceUrl(byAdmitGuid.getFaceUrl())
                    .setClasses(byAdmitGuid.getClasses())
                    .setWorkNumber(byAdmitGuid.getWorkNumber()).setClassesType(byId.getClassesType());
            IdentificationRecord todayEarlyByAdmitGuid = identificationRecordService.getTodayEarlyByAdmitGuid(admitGuid);
            if (todayEarlyByAdmitGuid != null) {
                clockRecord.setInTime(DateUtils.formatDate(todayEarlyByAdmitGuid.getTime(), "HH:mm:ss"));
                clockRecord.setInDate(DateUtils.formatDate(todayEarlyByAdmitGuid.getTime(), "yyyy-MM-dd"));
            }
            IdentificationRecord todayLastByAdmitGuid = identificationRecordService.getTodayLastByAdmitGuid(admitGuid);
            if (todayLastByAdmitGuid != null) {
                clockRecord.setOutTime(DateUtils.formatDate(todayLastByAdmitGuid.getTime(), "HH:mm:ss"));
                clockRecord.setOutDate(DateUtils.formatDate(todayLastByAdmitGuid.getTime(), "yyyy-MM-dd"));
            }
            saveList.add(clockRecord);
        }
        clockRecordService.saveBatch(saveList);
        log.info("生成成功");
    }


    /**
     * 编辑
     *
     * @param scheduling
     * @return
     */
    @AutoLog(value = "排班表-编辑")
    @ApiOperation(value = "排班表-编辑", notes = "排班表-编辑")
    @PutMapping(value = "/edit")
    public Result<?> edit(@RequestBody Scheduling scheduling) {
        String admitGuid = scheduling.getAdmitGuid();
        Date date = scheduling.getDate();
        LambdaQueryWrapper<Scheduling> schedulingWrapper = Wrappers.lambdaQuery();
        schedulingWrapper.eq(Scheduling::getAdmitGuid, admitGuid);
        schedulingWrapper.eq(Scheduling::getDate, date);
        List<Scheduling> schedulingList = schedulingService.list(schedulingWrapper);
        if (schedulingList.size() > 1){
            return Result.error("检测到当前人员于【" +DateUtils.formatDate(date)+ "】已存在排班记录");
        }
        LambdaQueryWrapper<ClockRecord> clockRecordWrapper = Wrappers.lambdaQuery();
        clockRecordWrapper.eq(ClockRecord::getAdmitGuid, admitGuid);
        clockRecordWrapper.eq(ClockRecord::getDate, date);
        List<ClockRecord> clockRecords = clockRecordService.list(clockRecordWrapper);
        if (clockRecords != null && !clockRecords.isEmpty()){
            if (clockRecords.size() > 1) {
                return Result.error("检测到当前人员于【" +DateUtils.formatDate(date)+ "】存在重复打卡记录,请先删除重复数据");
            }
            String classesId = scheduling.getClassesId();
            Classes classes = classesService.getById(classesId);
            ClockRecord clockRecord = clockRecords.get(0);
            clockRecord.setClassesId(classesId);
            clockRecord.setClassesType(classes.getClassesType());
            String inTime = clockRecord.getInTime();
            String startTime = classes.getStartTime();
            if (!StringUtils.isEmpty(inTime)){
                if (inTime.compareTo(startTime) <= 0) {
                    clockRecord.setAbnormalType(1).setAbnormal(0);
                } else {
                    clockRecord.setAbnormalType(3).setAbnormal(1);
                }
            }
            clockRecordService.updateById(clockRecord);
        }
        schedulingService.updateById(scheduling);
        return Result.OK("编辑成功!");
    }

    /**
     * 通过id删除
     *
     * @param id
     * @return
     */
    @AutoLog(value = "排班表-通过id删除")
    @ApiOperation(value = "排班表-通过id删除", notes = "排班表-通过id删除")
    @DeleteMapping(value = "/delete")
    public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
        schedulingService.removeById(id);
        return Result.OK("删除成功!");
    }

    /**
     * 批量删除
     *
     * @param ids
     * @return
     */
    @AutoLog(value = "排班表-批量删除")
    @ApiOperation(value = "排班表-批量删除", notes = "排班表-批量删除")
    @DeleteMapping(value = "/deleteBatch")
    public Result<?> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
        this.schedulingService.removeByIds(Arrays.asList(ids.split(",")));
        return Result.OK("批量删除成功!");
    }

    /**
     * 通过id查询
     *
     * @param id
     * @return
     */
    @AutoLog(value = "排班表-通过id查询")
    @ApiOperation(value = "排班表-通过id查询", notes = "排班表-通过id查询")
    @GetMapping(value = "/queryById")
    public Result<?> queryById(@RequestParam(name = "id", required = true) String id) {
        Scheduling scheduling = schedulingService.getById(id);
        if (scheduling == null) {
            return Result.error("未找到对应数据");
        }
        return Result.OK(scheduling);
    }

    /**
     * 导出excel
     *
     * @param request
     * @param scheduling
     */
    @RequestMapping(value = "/exportXls")
    public ModelAndView exportXls(HttpServletRequest request, Scheduling scheduling) {
        return super.exportXls(request, scheduling, Scheduling.class, "排班表");
    }

    /**
     * 通过excel导入数据
     *
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
    public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
        return super.importExcel(request, response, Scheduling.class);
    }

}
